using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Common.Shared.Reflection;

namespace Common.Shared.Tests {
	public class InvokeWithRetryTests {
		public InvokeWithRetryTests ( ) {
		}
		[Fact]
		public void FinalInvokePassTest ( ) {
			TestClass tc = new TestClass ( );
			Assert.DoesNotThrow ( delegate ( ) { 
				MethodInvoker.InvokeWithRetry<TestClass> ( tc, "FailPassNoReturn", new object[] { 5 }, 5 ); 
			} );
			tc = new TestClass ( );
			Assert.DoesNotThrow(delegate () {
				bool result = MethodInvoker.InvokeWithRetry<TestClass,bool> ( tc, "FailPassReturn", new object[] { 5 }, 5 );
				if ( !result ) {
					throw new Exception ( "why are we here?" );
				}
			} );
		}

		[Fact]
		public void AlwaysFailNoReturnTest ( ) {
			TestClass tc = new TestClass ( );
			Assert.Throws<TestClass.InvokeTestException> ( delegate ( ) {
				MethodInvoker.InvokeWithRetry<TestClass> ( tc, "AlwaysFailNoReturn", 5 );
			} );
		}

		[Fact]
		public void InvalidMethodNameTest ( ) {
			TestClass tc = new TestClass ( );
			Assert.Throws<MissingMethodException> ( delegate ( ) {
				MethodInvoker.InvokeWithRetry<TestClass> ( tc, "BadMethodName" );
			} );
		}

		[Fact]
		public void SimpleInvokeTest ( ) {
			TestClass tc = new TestClass ( );
			Assert.DoesNotThrow ( delegate ( ) {
				MethodInvoker.SimpleInvokeWithRetry ( tc, "FailPassNoReturn", new object[] { 5 }, 5 );
			} );

			Assert.Throws<TestClass.InvokeTestException> ( delegate ( ) {
				MethodInvoker.SimpleInvoke ( tc, "AlwaysFailNoReturn" );
			} );

			Assert.Throws<TestClass.InvokeTestException> ( delegate ( ) {
				object foo = MethodInvoker.SimpleInvoke ( tc, "AlwaysFailNoReturn" );
			} );
		}


		public class TestClass {
			public class InvokeTestException : Exception {
				public InvokeTestException ( ) : base ( string.Format("Invoke Exception : {0}",DateTime.Now.ToString())) {

				}

				public InvokeTestException ( string message ) : base(message) {

				}
			}

			int count = 0;
			public void FailPassNoReturn ( int passNumber ) {
				if ( ++count == passNumber ) {
					return;
				}

				throw new InvokeTestException ( string.Format ( "Failed because {0} != {1}", count, passNumber ) );
			}

			public void AlwaysFailNoReturn ( ) {
				throw new InvokeTestException ( "AlwaysFailNoReturn: Failed" );
			}

			public bool FailPassReturn ( int passNumber ) {
				if ( ++count == passNumber ) {
					return true;
				}

				throw new InvokeTestException ( string.Format ( "Failed because {0} != {1}", count, passNumber ) );
			}
		}
	}


}
